#include <fstream>
#include <iostream>
#include <filesystem>
#include <glad/glad.h>
#include "structs/shader_program.h"

//
// 着色器代码加载器
// Created by wang.yishu on 25-1-21.
//
const static std::string VERTEX_SHADER_SUFFIX = "_vertex.glsl";
const static std::string FRAGMENT_SHADER_SUFFIX = "_fragment.glsl";
const static std::string PATH = std::string(__FILE__);
const static std::filesystem::path current_path = std::filesystem::path(PATH);
const static std::filesystem::path parent_path = current_path.parent_path().parent_path().parent_path();
class ShaderLoader {
    public:
    ShaderLoader();
    ~ShaderLoader();

    /**
     * 载入shader
     * @param prefix
     * @param shaderName
     * @return
     */
    static shader_program* load_shader(const std:: string& prefix, const std::string& shaderName) {
        auto basic_path = parent_path.string() + "/shaders/" + prefix + "/";
        std::ifstream vertexFile(basic_path + shaderName + VERTEX_SHADER_SUFFIX);
        std::ifstream fragmentFile( basic_path + shaderName + FRAGMENT_SHADER_SUFFIX);
        if (!vertexFile.is_open()) {
            std::cerr << "Error opening file " << shaderName << VERTEX_SHADER_SUFFIX << std::endl;
            return nullptr;
        }
        if (!fragmentFile.is_open()) {
            std::cerr << "Error opening file " << shaderName << FRAGMENT_SHADER_SUFFIX << std::endl;
            return nullptr;
        }
        std::string vertexCode;
        std::string fragmentCode;
        std::string vertexCodeLine;
        std::string fragmentCodeLine;
        while (std::getline(vertexFile, vertexCodeLine)) {
            vertexCode += vertexCodeLine;
        }
        while (std::getline(fragmentFile, fragmentCodeLine)) {
            fragmentCode += fragmentCodeLine;
        }
        auto* shader = new shader_program();
        shader->name = shaderName;
        const GLchar* vShaderCode = vertexCode.c_str();
        shader->vertex_code = &vShaderCode;
        const GLchar* fShaderCode = fragmentCode.c_str();
        shader->fragment_code = &fShaderCode;
        return shader;
    }

    /**
         * 载入shader
         * @param prefix
         * @param shaderName
         * @return
         */
    static shader_program* load_shader(const std::string& shaderName) {
        auto basic_path = parent_path.string() + "/shaders/";
        std::ifstream vertexFile(basic_path + shaderName + VERTEX_SHADER_SUFFIX);
        std::ifstream fragmentFile( basic_path + shaderName + FRAGMENT_SHADER_SUFFIX);
        if (!vertexFile.is_open()) {
            std::cerr << "Error opening file " << shaderName << VERTEX_SHADER_SUFFIX << std::endl;
        }
        if (!fragmentFile.is_open()) {
            std::cerr << "Error opening file " << shaderName << FRAGMENT_SHADER_SUFFIX << std::endl;
        }
        std::string vertexCode;
        std::string fragmentCode;
        std::string vertexCodeLine;
        std::string fragmentCodeLine;
        while (std::getline(vertexFile, vertexCodeLine)) {
            vertexCode += vertexCodeLine;
        }
        while (std::getline(fragmentFile, fragmentCodeLine)) {
            fragmentCode += fragmentCodeLine;
        }
        auto* shader = new shader_program();
        shader->name = shaderName;
        const GLchar* vShaderCode = vertexCode.c_str();
        shader->vertex_code = &vShaderCode;
        const GLchar* fShaderCode = fragmentCode.c_str();
        shader->fragment_code = &fShaderCode;
        return shader;
    }
};